#include <iostream>
#include <ctime>
#include <fstream>
#include <algorithm>
#include <seqan/sequence.h>
#include <seqan/file.h>
#include <seqan/translation.h>
#include <seqan/graph_align.h>
#include <seqan/graph_msa.h>
#include <seqan/seq_io.h>
#include <seqan/stream.h>

using std::string;
using std::ifstream;
using std::cerr;
using std::cout;
using std::endl;
using std::count_if;
using std::ofstream;
using seqan::StringSet;
using seqan::CharString;
using seqan::DnaString;
using seqan::RecordReader;
using seqan::SinglePass;
using seqan::Fasta;
using seqan::GenBank;
using seqan::GenBankHeader;
using seqan::SimpleType;
using seqan::Dna_;
using seqan::Peptide;
using seqan::Align;
using seqan::Blosum62;
using seqan::RnaString;

void Read_Files(int argc, char** argv, StringSet<CharString>& headers, StringSet<DnaString>& dnas)
{
	clear(headers);
	clear(dnas);

	for (size_t i = 1; i < argc; ++i)
	{
		string next_file(argv[i]);
		ifstream next_file_stream(next_file);
		RecordReader<ifstream, SinglePass<>> reader(next_file_stream);
		string extension = next_file.substr(next_file.rfind('.') + 1);

		CharString header;
		DnaString dna;
		if (extension == "fasta")
		{
			readRecord(header, dna, reader, Fasta());
		}
		else if (extension == "gb")
		{
			CharString buffer, key;
			readRecord(buffer, reader, GenBankHeader());
			splitGenBankHeader(key, header, buffer);
			readRecord(buffer, dna, reader, GenBank());
		}
		else
		{
			cerr << "Unsupported file type" << endl;
			throw;
		}

		appendValue(headers, header);
		appendValue(dnas, dna);
		next_file_stream.close();
	}
}

void Print_CG_Content(StringSet<DnaString>& dnas, StringSet<CharString> const& headers)
{
	cout << "CG Content:\n";
	size_t i = 0;
	for (DnaString dna : dnas)
	{
		cout << headers[i++] << endl;
		double cg_content = count_if(dna.data_begin, dna.data_end, [](SimpleType<unsigned char, Dna_>& next)
		{
			return next == 'C' || next == 'G';
		}) / (double)length(dna);

		cout << cg_content << endl;
	}
}

bool Check_Input_Args(int argc, char** argv)
{
	if (argc < 3)
	{
		cerr << "You should specify at least two files" << endl;
		return false;
	}

	for (size_t i = 1; i < argc; ++i)
	{
		ifstream test(argv[i]);

		if (!test.good())
		{
			cerr << "Something wrong with " << i << "th file" << endl;
			return false;
		}

		test.close();
	}

	return true;
}

void Print_Delimiter()
{
	cout << "-----------------------------------------------------------------\n";
}

int main(int argc, char** argv)
{
	if (!Check_Input_Args(argc, argv))
	{
		return 1;
	}

	StringSet<CharString> headers;
	StringSet<DnaString> dnas;
	Read_Files(argc, argv, headers, dnas);

	Print_CG_Content(dnas, headers);

	Print_Delimiter();
	cout << "RNA:\n";
	size_t i = 0;
	for (auto& next : dnas)
	{
		RnaString rna;
		assign(rna, next);
		cout << headers[i++] << endl;
		cout << rna << endl;
	}

	StringSet<Peptide> peptides;
	translate(peptides, dnas);

	Print_Delimiter();
	cout << "Peptides:\n";
	i = 0;
	for (auto& next : peptides)
	{
		cout << headers[i++] << endl;
		cout << next << endl;
	}

	Print_Delimiter();
	cout << "Alignment:\n";

	Align<Peptide> align(peptides);
	globalMsaAlignment(align, Blosum62());
	cout << align << endl;

	ofstream output_file("out.phylip");
	output_file << length(headers) << " " << length(align.data_rows[0]) << endl;
	for (size_t i = 0; i < length(headers); ++i)
	{
		output_file << headers[i] << endl << align.data_rows[i] << endl;
	}
	output_file.close();
}